/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstddef>
#include <cstdint>

#include "animate_impl.h"
#include "native_type.h"
#include "node/node_model.h"

#include "base/error/error_code.h"
#include "base/utils/utils.h"
#ifdef __cplusplus
extern "C" {
#endif

Keels_ArkUI_AnimateOption* Keels_ArkUI_AnimateOption_Create()
{
    Keels_ArkUI_AnimateOption* option = new Keels_ArkUI_AnimateOption;
    // duration default 1000
    option->duration = 1000;
    // tempo default 1.0
    option->tempo = 1.0f;
    option->curve = Keels_ArkUI_AnimationCurve::KEELS_ARKUI_CURVE_EASE_IN_OUT;
    // delay default 0
    option->delay = 0;
    // iterations default 1
    option->iterations = 1;
    option->playMode = Keels_ArkUI_AnimationPlayMode::KEELS_ARKUI_ANIMATION_PLAY_MODE_NORMAL;
    option->expectedFrameRateRange = nullptr;
    option->iCurve = nullptr;
    return option;
}

void Keels_ArkUI_AnimateOption_Dispose(Keels_ArkUI_AnimateOption* option)
{
    if (option == nullptr) {
        return;
    }
    if (option->expectedFrameRateRange != nullptr) {
        delete option->expectedFrameRateRange;
        option->expectedFrameRateRange = nullptr;
    }
    delete option;
}

uint32_t Keels_ArkUI_AnimateOption_GetDuration(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, 0);
    return option->duration;
}

float Keels_ArkUI_AnimateOption_GetTempo(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, 0.0f);
    return option->tempo;
}

Keels_ArkUI_AnimationCurve Keels_ArkUI_AnimateOption_GetCurve(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, static_cast<Keels_ArkUI_AnimationCurve>(-1));
    return option->curve;
}

int32_t Keels_ArkUI_AnimateOption_GetDelay(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, 0);
    return option->delay;
}

int32_t Keels_ArkUI_AnimateOption_GetIterations(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, 0);
    return option->iterations;
}

Keels_ArkUI_AnimationPlayMode Keels_ArkUI_AnimateOption_GetPlayMode(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, static_cast<Keels_ArkUI_AnimationPlayMode>(-1));
    return option->playMode;
}

Keels_ArkUI_ExpectedFrameRateRange* Keels_ArkUI_AnimateOption_GetExpectedFrameRateRange(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, nullptr);
    return option->expectedFrameRateRange;
}

void Keels_ArkUI_AnimateOption_SetDuration(Keels_ArkUI_AnimateOption* option, int32_t value)
{
    CHECK_NULL_VOID(option);
    // 设置小于0的值时按0处理
    if (value < 0) {
        value = 0;
    }
    option->duration = static_cast<uint32_t>(value);
}

void Keels_ArkUI_AnimateOption_SetTempo(Keels_ArkUI_AnimateOption* option, float value)
{
    CHECK_NULL_VOID(option);
    // 小于0的值时按值为1处理
    if (value < 0) {
        value = 1;
    }
    option->tempo = value;
}

void Keels_ArkUI_AnimateOption_SetCurve(Keels_ArkUI_AnimateOption* option, Keels_ArkUI_AnimationCurve value)
{
    CHECK_NULL_VOID(option);
    if (value >= KEELS_ARKUI_CURVE_LINEAR && value <= KEELS_ARKUI_CURVE_FRICTION) {
        option->curve = value;
    }
}

void Keels_ArkUI_AnimateOption_SetDelay(Keels_ArkUI_AnimateOption* option, int32_t value)
{
    CHECK_NULL_VOID(option);
    option->delay = value;
}

void Keels_ArkUI_AnimateOption_SetIterations(Keels_ArkUI_AnimateOption* option, int32_t value)
{
    CHECK_NULL_VOID(option);
    //取值范围：[-1, +∞)
    if (value < -1) {
        return;
    }
    option->iterations = value;
}

void Keels_ArkUI_AnimateOption_SetPlayMode(Keels_ArkUI_AnimateOption* option, Keels_ArkUI_AnimationPlayMode value)
{
    CHECK_NULL_VOID(option);
    if (value >= KEELS_ARKUI_ANIMATION_PLAY_MODE_NORMAL && value <= KEELS_ARKUI_ANIMATION_PLAY_MODE_ALTERNATE_REVERSE) {
        option->playMode = value;
    }
}

void Keels_ArkUI_AnimateOption_SetExpectedFrameRateRange(Keels_ArkUI_AnimateOption* option, Keels_ArkUI_ExpectedFrameRateRange* value)
{
    CHECK_NULL_VOID(option);
    CHECK_NULL_VOID(value);
    option->expectedFrameRateRange = new Keels_ArkUI_ExpectedFrameRateRange { value->min, value->max, value->expected };
}

void Keels_ArkUI_AnimateOption_SetICurve(Keels_ArkUI_AnimateOption* option, Keels_ArkUI_CurveHandle value)
{
    CHECK_NULL_VOID(option);
    CHECK_NULL_VOID(value);
    option->iCurve = value;
}

Keels_ArkUI_CurveHandle Keels_ArkUI_AnimateOption_GetICurve(Keels_ArkUI_AnimateOption* option)
{
    CHECK_NULL_RETURN(option, nullptr);
    return option->iCurve;
}

Keels_ArkUI_KeyframeAnimateOption* Keels_ArkUI_KeyframeAnimateOption_Create(int32_t size)
{
    if (size < 0) {
        return nullptr;
    }

    Keels_ArkUI_KeyframeAnimateOption* animateOption = new Keels_ArkUI_KeyframeAnimateOption;
    animateOption->keyframes.resize(size);
    animateOption->delay = 0;
    animateOption->iterations = 1;
    animateOption->onFinish = nullptr;
    animateOption->userData = nullptr;

    for (int32_t i = 0; i < size; ++i) {
        // duration default 1000
        animateOption->keyframes[i].duration = 1000;
        animateOption->keyframes[i].curve = nullptr;
        animateOption->keyframes[i].event = nullptr;
        animateOption->keyframes[i].userData = nullptr;
    }
    return animateOption;
}

void Keels_ArkUI_KeyframeAnimateOption_Dispose(Keels_ArkUI_KeyframeAnimateOption* option)
{
    CHECK_NULL_VOID(option);
    delete option;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_SetDelay(Keels_ArkUI_KeyframeAnimateOption* option, int32_t value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    option->delay = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_SetIterations(Keels_ArkUI_KeyframeAnimateOption* option, int32_t value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    //取值范围：[-1, +∞)
    if (value < -1) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->iterations = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_RegisterOnFinishCallback(
    Keels_ArkUI_KeyframeAnimateOption* option, void* userData, void (*onFinish)(void* userData))
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    option->onFinish = onFinish;
    option->userData = userData;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_SetDuration(Keels_ArkUI_KeyframeAnimateOption* option, int32_t value, int32_t index)
{
    if (option == nullptr || index < 0 || index >= static_cast<int32_t>(option->keyframes.size())) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    if (value < 0) {
        value = 0;
    }
    option->keyframes[index].duration = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_SetCurve(
    Keels_ArkUI_KeyframeAnimateOption* option, Keels_ArkUI_CurveHandle value, int32_t index)
{
    if (option == nullptr || index < 0 || index >= static_cast<int32_t>(option->keyframes.size())) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    if (!value || !value->curve) {
        option->keyframes[index].curve = nullptr;
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    if (value->type == ARKUI_CURVE_TYPE_SPRING_MOTION || value->type == ARKUI_CURVE_TYPE_RESPONSIVE_SPRING_MOTION ||
        value->type == ARKUI_CURVE_TYPE_INTERPOLATING_SPRING) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->keyframes[index].curve = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_RegisterOnEventCallback(
    Keels_ArkUI_KeyframeAnimateOption* option, void* userData, void (*event)(void* userData), int32_t index)
{
    if (option == nullptr || index < 0 || index >= static_cast<int32_t>(option->keyframes.size())) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->keyframes[index].event = event;
    option->keyframes[index].userData = userData;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_GetDelay(Keels_ArkUI_KeyframeAnimateOption* option)
{
    CHECK_NULL_RETURN(option, 0);
    return option->delay;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_GetIterations(Keels_ArkUI_KeyframeAnimateOption* option)
{
    CHECK_NULL_RETURN(option, 1);
    return option->iterations;
}

int32_t Keels_ArkUI_KeyframeAnimateOption_GetDuration(Keels_ArkUI_KeyframeAnimateOption* option, int32_t index)
{
    if (option == nullptr || index < 0 || index >= static_cast<int32_t>(option->keyframes.size())) {
        return 0;
    }
    return option->keyframes[index].duration;
}

Keels_ArkUI_CurveHandle Keels_ArkUI_KeyframeAnimateOption_GetCurve(Keels_ArkUI_KeyframeAnimateOption* option, int32_t index)
{
    if (option == nullptr || index < 0 || index >= static_cast<int32_t>(option->keyframes.size())) {
        return nullptr;
    }
    return option->keyframes[index].curve;
}

Keels_ArkUI_AnimatorOption* Keels_ArkUI_AnimatorOption_Create(int32_t keyframeSize)
{
    if (keyframeSize < 0) {
        return nullptr;
    }

    Keels_ArkUI_AnimatorOption* option = new Keels_ArkUI_AnimatorOption;
    option->keyframes.resize(keyframeSize);
    for (int32_t i = 0; i < keyframeSize; i++) {
        option->keyframes[i].curve = nullptr;
    }
    option->duration = 0;
    option->delay = 0;
    option->iterations = 1;
    option->fill = KEELS_ARKUI_ANIMATION_FILL_MODE_FORWARDS;
    option->direction = KEELS_ARKUI_ANIMATION_DIRECTION_NORMAL;
    option->begin = 0.0f;
    option->end = 1.0f;
    option->easing = nullptr;
    option->onFrame = nullptr;
    option->frameUserData = nullptr;
    option->onFinish = nullptr;
    option->finishUserData = nullptr;
    option->onCancel = nullptr;
    option->cancelUserData = nullptr;
    option->onRepeat = nullptr;
    option->repeatUserData = nullptr;
    option->expectedFrameRateRange = nullptr;
    return option;
}

void Keels_ArkUI_AnimatorOption_Dispose(Keels_ArkUI_AnimatorOption* option)
{
    CHECK_NULL_VOID(option);
    if (option->expectedFrameRateRange) {
        delete option->expectedFrameRateRange;
        option->expectedFrameRateRange = nullptr;
    }
    delete option;
}

int32_t Keels_ArkUI_AnimatorOption_SetDuration(Keels_ArkUI_AnimatorOption* option, int32_t value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (value < 0) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->duration = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetDelay(Keels_ArkUI_AnimatorOption* option, int32_t value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    option->delay = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetIterations(Keels_ArkUI_AnimatorOption* option, int32_t value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (value < -1) {
        value = 1;
    }
    option->iterations = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetFill(Keels_ArkUI_AnimatorOption* option, Keels_ArkUI_AnimationFillMode value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (value > KEELS_ARKUI_ANIMATION_FILL_MODE_BOTH || value < KEELS_ARKUI_ANIMATION_FILL_MODE_NONE) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->fill = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetDirection(Keels_ArkUI_AnimatorOption* option, Keels_ArkUI_AnimationDirection value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (value > KEELS_ARKUI_ANIMATION_DIRECTION_ALTERNATE_REVERSE || value < KEELS_ARKUI_ANIMATION_DIRECTION_NORMAL) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->direction = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetCurve(Keels_ArkUI_AnimatorOption* option, Keels_ArkUI_CurveHandle value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (value) {
        if (value->type == ARKUI_CURVE_TYPE_SPRING || value->type == ARKUI_CURVE_TYPE_SPRING_MOTION ||
            value->type == ARKUI_CURVE_TYPE_RESPONSIVE_SPRING_MOTION ||
            value->type == ARKUI_CURVE_TYPE_INTERPOLATING_SPRING || value->type == ARKUI_CURVE_TYPE_CUSTOM) {
            option->easing = nullptr;
            return Keels::Ace::ERROR_CODE_PARAM_INVALID;
        }
    }

    option->easing = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetBegin(Keels_ArkUI_AnimatorOption* option, float value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (option->keyframes.size() > 0) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->begin = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetEnd(Keels_ArkUI_AnimatorOption* option, float value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (option->keyframes.size() > 0) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->end = value;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetExpectedFrameRateRange(
    Keels_ArkUI_AnimatorOption* option, Keels_ArkUI_ExpectedFrameRateRange* value)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    CHECK_NULL_RETURN(value, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    option->expectedFrameRateRange = new Keels_ArkUI_ExpectedFrameRateRange { value->min, value->max, value->expected };
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_SetKeyframe(Keels_ArkUI_AnimatorOption* option, float time, float value, int32_t index)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (time < 0 || time > 1) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    if (index >= 0 && static_cast<size_t>(index) < option->keyframes.size()) {
        option->keyframes[index].keyTime = time;
        option->keyframes[index].keyValue = value;
        return Keels::Ace::ERROR_CODE_NO_ERROR;
    }
    return Keels::Ace::ERROR_CODE_PARAM_INVALID;
}

int32_t Keels_ArkUI_AnimatorOption_SetKeyframeCurve(Keels_ArkUI_AnimatorOption* option, Keels_ArkUI_CurveHandle value, int32_t index)
{
    CHECK_NULL_RETURN(option, Keels::Ace::ERROR_CODE_PARAM_INVALID);
    if (value) {
        if (value->type == ARKUI_CURVE_TYPE_SPRING || value->type == ARKUI_CURVE_TYPE_SPRING_MOTION ||
            value->type == ARKUI_CURVE_TYPE_RESPONSIVE_SPRING_MOTION ||
            value->type == ARKUI_CURVE_TYPE_INTERPOLATING_SPRING || value->type == ARKUI_CURVE_TYPE_CUSTOM) {
            option->keyframes[index].curve = nullptr;
            return Keels::Ace::ERROR_CODE_PARAM_INVALID;
        }
    }

    if (index >= 0 && static_cast<size_t>(index) < option->keyframes.size()) {
        option->keyframes[index].curve = value;
        return Keels::Ace::ERROR_CODE_NO_ERROR;
    }
    return Keels::Ace::ERROR_CODE_PARAM_INVALID;
}

int32_t Keels_ArkUI_AnimatorOption_GetDuration(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->duration;
    }
    return -1;
}

int32_t Keels_ArkUI_AnimatorOption_GetDelay(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->delay;
    }
    return -1;
}

int32_t Keels_ArkUI_AnimatorOption_GetIterations(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->iterations;
    }
    return -1;
}

Keels_ArkUI_AnimationFillMode Keels_ArkUI_AnimatorOption_GetFill(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->fill;
    }
    return static_cast<Keels_ArkUI_AnimationFillMode>(-1);
}

Keels_ArkUI_AnimationDirection Keels_ArkUI_AnimatorOption_GetDirection(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->direction;
    }
    return static_cast<Keels_ArkUI_AnimationDirection>(-1);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_AnimatorOption_GetCurve(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->easing;
    }
    return nullptr;
}

float Keels_ArkUI_AnimatorOption_GetBegin(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->begin;
    }
    return 0.0f;
}

float Keels_ArkUI_AnimatorOption_GetEnd(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->end;
    }
    return 1.0f;
}

Keels_ArkUI_ExpectedFrameRateRange* Keels_ArkUI_AnimatorOption_GetExpectedFrameRateRange(Keels_ArkUI_AnimatorOption* option)
{
    if (option != nullptr) {
        return option->expectedFrameRateRange;
    }
    return nullptr;
}

float Keels_ArkUI_AnimatorOption_GetKeyframeTime(Keels_ArkUI_AnimatorOption* option, int32_t index)
{
    if (option != nullptr && index >= 0 && static_cast<size_t>(index) < option->keyframes.size()) {
        return option->keyframes[index].keyTime;
    }
    return -1.0f;
}

float Keels_ArkUI_AnimatorOption_GetKeyframeValue(Keels_ArkUI_AnimatorOption* option, int32_t index)
{
    if (option != nullptr && index >= 0 && static_cast<size_t>(index) < option->keyframes.size()) {
        return option->keyframes[index].keyValue;
    }
    return -1.0f;
}

Keels_ArkUI_CurveHandle Keels_ArkUI_AnimatorOption_GetKeyframeCurve(Keels_ArkUI_AnimatorOption* option, int32_t index)
{
    if (option != nullptr && index >= 0 && static_cast<size_t>(index) < option->keyframes.size()) {
        return option->keyframes[index].curve;
    }
    return nullptr;
}

void* Keels_ArkUI_AnimatorEvent_GetUserData(Keels_ArkUI_AnimatorEvent* event)
{
    CHECK_NULL_RETURN(event, nullptr);
    return event->userData;
}

void* Keels_ArkUI_AnimatorOnFrameEvent_GetUserData(Keels_ArkUI_AnimatorOnFrameEvent* event)
{
    CHECK_NULL_RETURN(event, nullptr);
    return event->userData;
}

float Keels_ArkUI_AnimatorOnFrameEvent_GetValue(Keels_ArkUI_AnimatorOnFrameEvent* event)
{
    CHECK_NULL_RETURN(event, 0.0f);
    return event->progress;
}

int32_t Keels_ArkUI_AnimatorOption_RegisterOnFrameCallback(
    Keels_ArkUI_AnimatorOption* option, void* userData, void (*callback)(Keels_ArkUI_AnimatorOnFrameEvent* event))
{
    auto* impl = Keels::Ace::NodeModel::GetFullImpl();
    if (!impl || !option || !callback) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }
    option->onFrame = callback;
    option->frameUserData = userData;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_RegisterOnFinishCallback(
    Keels_ArkUI_AnimatorOption* option, void* userData, void (*callback)(Keels_ArkUI_AnimatorEvent* event))
{
    auto* impl = Keels::Ace::NodeModel::GetFullImpl();
    if (!impl || !option || !callback) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }

    option->onFinish = callback;
    option->finishUserData = userData;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_RegisterOnCancelCallback(
    Keels_ArkUI_AnimatorOption* option, void* userData, void (*callback)(Keels_ArkUI_AnimatorEvent* event))
{
    auto* impl = Keels::Ace::NodeModel::GetFullImpl();
    if (!impl || !option || !callback) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }

    option->onCancel = callback;
    option->cancelUserData = userData;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_AnimatorOption_RegisterOnRepeatCallback(
    Keels_ArkUI_AnimatorOption* option, void* userData, void (*callback)(Keels_ArkUI_AnimatorEvent* event))
{
    auto* impl = Keels::Ace::NodeModel::GetFullImpl();
    if (!impl || !option || !callback) {
        return Keels::Ace::ERROR_CODE_PARAM_INVALID;
    }

    option->onRepeat = callback;
    option->repeatUserData = userData;
    return Keels::Ace::ERROR_CODE_NO_ERROR;
}

int32_t Keels_ArkUI_Animator_ResetAnimatorOption(Keels_ArkUI_AnimatorHandle animator, Keels_ArkUI_AnimatorOption* option)
{
    return Keels::Ace::AnimateModel::AnimatorReset(animator, option);
}

int32_t Keels_ArkUI_Animator_Play(Keels_ArkUI_AnimatorHandle animator)
{
    return Keels::Ace::AnimateModel::AnimatorPlay(animator);
}

int32_t Keels_ArkUI_Animator_Finish(Keels_ArkUI_AnimatorHandle animator)
{
    return Keels::Ace::AnimateModel::AnimatorFinish(animator);
}

int32_t Keels_ArkUI_Animator_Pause(Keels_ArkUI_AnimatorHandle animator)
{
    return Keels::Ace::AnimateModel::AnimatorPause(animator);
}

int32_t Keels_ArkUI_Animator_Cancel(Keels_ArkUI_AnimatorHandle animator)
{
    return Keels::Ace::AnimateModel::AnimatorCancel(animator);
}

int32_t Keels_ArkUI_Animator_Reverse(Keels_ArkUI_AnimatorHandle animator)
{
    return Keels::Ace::AnimateModel::AnimatorReverse(animator);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateCurveByType(Keels_ArkUI_AnimationCurve curve)
{
    return Keels::Ace::AnimateModel::InitCurve(curve);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateStepsCurve(int32_t count, bool end)
{
    return Keels::Ace::AnimateModel::StepsCurve(count, end);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateCubicBezierCurve(float x1, float y1, float x2, float y2)
{
    return Keels::Ace::AnimateModel::CubicBezierCurve(x1, y1, x2, y2);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateSpringCurve(float velocity, float mass, float stiffness, float damping)
{
    return Keels::Ace::AnimateModel::SpringCurve(velocity, mass, stiffness, damping);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateSpringMotion(float response, float dampingFraction, float overlapDuration)
{
    return Keels::Ace::AnimateModel::SpringMotion(response, dampingFraction, overlapDuration);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateResponsiveSpringMotion(
    float response, float dampingFraction, float overlapDuration)
{
    return Keels::Ace::AnimateModel::ResponsiveSpringMotion(response, dampingFraction, overlapDuration);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateInterpolatingSpring(float velocity, float mass, float stiffness, float damping)
{
    return Keels::Ace::AnimateModel::InterpolatingSpring(velocity, mass, stiffness, damping);
}

Keels_ArkUI_CurveHandle Keels_ArkUI_Curve_CreateCustomCurve(void* userData, float (*interpolate)(float fraction, void* userdata))
{
    return Keels::Ace::AnimateModel::CustomCurve(userData, interpolate);
}

void Keels_ArkUI_Curve_DisposeCurve(Keels_ArkUI_CurveHandle curveHandle)
{
    return Keels::Ace::AnimateModel::DisposeCurve(curveHandle);
}

#ifdef __cplusplus
};
#endif